#include "threading_Condition.h"
#include "pika_platform_thread.h"



void threading_Condition___init__(PikaObj *self){
    pika_platform_thread_cond_t* cond = pikaMalloc(sizeof(pika_platform_thread_cond_t));
    int err = pika_platform_thread_cond_init(cond);
    if (err == PIKA_RES_ERR_MEMORY_ERROR){
        obj_raise(self, PIKA_RES_ERR_RUNTIME_ERROR, "malloc fail.");
        return;
    }
    obj_setPtr(self, "cond", cond);
}
pika_bool threading_Condition_acquire(PikaObj *self, pika_bool block, Arg* timeout){
    ArgType timout_type = arg_getType(timeout);
    pika_float timeout_f;
    if (timout_type == ARG_TYPE_FLOAT){
        timeout_f = arg_getFloat(timeout);
        if (timeout_f < 0.0){
            obj_raise(self, PIKA_RES_ERR_VALUE_ERROR, "timeout shouldn't less than 0.");
            return pika_false;
        }
    }
    else if (timout_type == ARG_TYPE_INT){
        timeout_f = (pika_float)arg_getInt(timeout);
        if (timeout_f < 0.0){
            obj_raise(self, PIKA_RES_ERR_VALUE_ERROR, "timeout shouldn't less than 0.");
            return pika_false;
        }
    }
    else if (timout_type == ARG_TYPE_NONE){
        timeout_f = -1;
    }
    else{
        obj_raise(self, PIKA_RES_ERR_TYPE_ERROR, "float, int or None is required.");
        return pika_false;
    }

    pika_platform_thread_cond_t* cond = obj_getPtr(self, "cond");
    int err = pika_platform_thread_cond_acquire(cond, block, timeout_f);
    if (err == PIKA_RES_OK){
        return pika_true;
    }
    else{
        obj_raise(self, PIKA_RES_ERR_RUNTIME_ERROR, "acquire fail.");
        return pika_false;
    }
}
void threading_Condition_notify(PikaObj *self, int n){
    pika_platform_thread_cond_t* cond = obj_getPtr(self, "cond");
    int err = pika_platform_thread_cond_notify(cond, n);
    if (err == PIKA_RES_ERR_RUNTIME_ERROR){
        obj_raise(self, PIKA_RES_ERR_RUNTIME_ERROR, "cannot notify on un-acquired lock.");
    }
}
void threading_Condition_notify_all(PikaObj *self){
    pika_platform_thread_cond_t* cond = obj_getPtr(self, "cond");
    int err = pika_platform_thread_cond_notify_all(cond);
    if (err == PIKA_RES_ERR_RUNTIME_ERROR){
        obj_raise(self, PIKA_RES_ERR_RUNTIME_ERROR, "cannot notify on un-acquired lock.");
    }
}
void threading_Condition_release(PikaObj *self){
    pika_platform_thread_cond_t* cond = obj_getPtr(self, "cond");
    pika_platform_thread_cond_release(cond);
}
pika_bool threading_Condition_wait(PikaObj *self, Arg* timeout){

    ArgType timout_type = arg_getType(timeout);
    pika_float timeout_f;
    if (timout_type == ARG_TYPE_FLOAT){
        timeout_f = arg_getFloat(timeout);
        if (timeout_f < 0.0){
            obj_raise(self, PIKA_RES_ERR_VALUE_ERROR, "timeout shouldn't less than 0.");
            return pika_false;
        }
    }
    else if (timout_type == ARG_TYPE_INT){
        timeout_f = (pika_float)arg_getInt(timeout);
        if (timeout_f < 0.0){
            obj_raise(self, PIKA_RES_ERR_VALUE_ERROR, "timeout shouldn't less than 0.");
            return pika_false;
        }
    }
    else if (timout_type == ARG_TYPE_NONE){
        timeout_f = -1;
    }
    else{
        obj_raise(self, PIKA_RES_ERR_TYPE_ERROR, "float, int or None is required.");
        return pika_false;
    }

    pika_platform_thread_cond_t* cond = obj_getPtr(self, "cond");
    int err = pika_platform_thread_cond_wait(cond, timeout_f);
    if (err == PIKA_RES_OK){
        return pika_true;
    }
    else if (err == PIKA_RES_ERR_TIMEOUT){
        return pika_false;
    }
    else {
        obj_raise(self, PIKA_RES_ERR_RUNTIME_ERROR, "cannot wait on un-acquired lock.");
        return pika_false;
    }
}

void threading_Condition___del__(PikaObj *self){
    pika_platform_thread_cond_t* cond = obj_getPtr(self, "cond");
    pika_platform_thread_cond_destory(cond);
    pikaFree(cond, sizeof(pika_platform_thread_cond_t));
}